package com.bifang.core.quartz.config;

import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import lombok.Data;
import lombok.SneakyThrows;
import org.quartz.SchedulerException;
import org.quartz.utils.ConnectionProvider;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.ObjectUtils;

/**
 * @author lvxk
 * @date 2022-06-09
 * @description Druid连接池的Quartz扩展类
 */
@Data
public class DruidPoolingConnectionProvider implements ConnectionProvider {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * 常量配置，与quartz.properties文件的key保持一致(去掉前缀)，同时提供set方法，Quartz框架自动注入值。
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    public String driver;

    public int maxConnections;

    public String validationQuery;

    private boolean validateOnCheckout;

    private int idleConnectionValidationSeconds;

    public String maxCachedStatementsPerConnection;

    private String discardIdleConnectionsSeconds;

    public static final int DEFAULT_DB_MAX_CONNECTIONS = 10;

    public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;

    private DruidDataSource datasource;

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * 接口实现
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */
    /**
     * @return connection managed by this provider
     */
    @Override
    public Connection getConnection() throws SQLException {
        return datasource.getConnection();
    }

    @Override
    public void shutdown() {
        datasource.close();
    }

    @SneakyThrows
    @Override
    public void initialize() {
        ClassPathResource resource = new ClassPathResource("application.properties");
        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
        String activeKey = (String) properties.get("spring.profiles.active");
        ClassPathResource activeResource =
                new ClassPathResource("application-" + activeKey + ".properties");
        Properties activeProperties = PropertiesLoaderUtils.loadProperties(activeResource);
        ClassPathResource quartzResource = new ClassPathResource("config/quartz.properties");
        Properties quartzProperties = PropertiesLoaderUtils.loadProperties(quartzResource);
        String url;
        String driver;
        Object sqlPrintFlag = quartzProperties.get("spring.quartz.custom.sqlPrint");
        if (!ObjectUtils.isEmpty(sqlPrintFlag) && Boolean.parseBoolean((String) sqlPrintFlag)) {
            url =
                    ((String)
                            activeProperties.get(
                                    "spring.datasource.dynamic.datasource.master.url"));
            driver =
                    ((String)
                            activeProperties.get(
                                    "spring.datasource.dynamic.datasource.master.driver-class-name"));

        } else {
            url =
                    ((String)
                                    activeProperties.get(
                                            "spring.datasource.dynamic.datasource.master.url"))
                            .replace("p6spy:", "");
            driver = (String) this.driver;
        }
        String user =
                (String)
                        activeProperties.get(
                                "spring.datasource.dynamic.datasource.master.username");
        String password =
                (String)
                        activeProperties.get(
                                "spring.datasource.dynamic.datasource.master.password");

        if (this.maxConnections < 0) {
            throw new SQLException(
                    "DBPool maxConnections could not be created: Max connections must be greater than zero!");
        }

        datasource = new DruidDataSource();
        try {
            datasource.setDriverClassName(driver);
        } catch (Exception e) {
            try {
                throw new SchedulerException(
                        "Problem setting driver class name on datasource: " + e.getMessage(), e);
            } catch (SchedulerException e1) {
            }
        }

        datasource.setUrl(url);
        datasource.setUsername(user);
        datasource.setPassword(password);
        datasource.setMaxActive(this.maxConnections);
        datasource.setMinIdle(1);
        datasource.setMaxWait(0);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(DEFAULT_DB_MAX_CONNECTIONS);

        if (this.validationQuery != null) {
            datasource.setValidationQuery(this.validationQuery);
            if (!this.validateOnCheckout) {
                datasource.setTestOnReturn(true);
            } else {
                datasource.setTestOnBorrow(true);
            }
            datasource.setValidationQueryTimeout(this.idleConnectionValidationSeconds);
        }
    }
}
